﻿//Copyright (C) <2013>  <jonathan cleeve norton> All Rights Reserved 
//Contact jon.norton@fin-plus.co.uk website <http://www.fin-plus.co.uk/>
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Reflection;
using System.ComponentModel;
using u = FinPlusUtility.Utility;
using log = Logger.Logger;

namespace FinPlusCommon
{
    public static class FuncInfos 
    {
        public static IFinPlusFunctions Get(IFinPlusFunctions funcs, Assembly assembly = null)
        {
            var infos = new Functions();

            var order = 0; 
            foreach (var func in funcs.Values)
                infos.Add(FuncInfo.Get(func, assembly, infos.NextKey(), order++));

            return infos;
        }
    }

    public static class FuncInfo
    {
        private enum Params { FunctionInfo, Order, Function, FunctionName, Id, Parent, Children, Invoke, IsBuilt, IsValid, ChildCount, Exception, Properties, Methods, System }

        public static IFinPlusFunction Get(IFinPlusFunction func, Assembly assembly, int id = -1, int order = 0 )
        {
            var info = new Function(Params.FunctionInfo.ToString(), id.ToString(), Params.System.ToString(), id);
            info[Params.Order.ToString()] = order;
            info[Params.Function.ToString()] = (Function)func;
            info[Params.FunctionName.ToString()] = func[Params.FunctionName.ToString()];
            info[Params.Id.ToString()] = func[Params.Id.ToString()].ToString();
            info[Params.Parent.ToString()] = string.Join(",", func.Parents);
            info[Params.Children.ToString()] = string.Join(",", func.Children);
            info[Params.Invoke.ToString()] =  func.Invoke == null ? string.Empty : func.Invoke;
            info[Params.IsBuilt.ToString()] = 0;
            info[Params.IsValid.ToString()] = 0;
            info[Params.ChildCount.ToString()] = 0;
            info[Params.Exception.ToString()] = string.Empty;
            info[Params.Properties.ToString()] = new Function(Params.Properties.ToString());
            info[Params.Methods.ToString()] = new Function(Params.Methods.ToString());

            if (func.Object == null) return info;

            Exception e = null;
            IFinPlusComponent component = null;

            if (u.TryCast<Exception>(func.Object, null, out e))
            {
                info[Params.Exception.ToString()] = e.Message;
                info[Params.IsBuilt.ToString()] = -1;
            }
            else if (u.TryCast<IFinPlusComponent>(func.Object, null, out component))
            {
                info[Params.IsBuilt.ToString()] = 1;
                info[Params.IsValid.ToString()] = component.IsValid ? 1 : -1;
                info[Params.ChildCount.ToString()] = component.Model == null ? 0 : component.Model.Count();
                info[Params.Properties.ToString()] = GetProperties(func, assembly);
                info[Params.Methods.ToString()] = GetMethods(func, assembly);
            }
            else
            {
                info[Params.IsBuilt.ToString()] = 1;
                info[Params.Properties.ToString()] = GetProperties(func, assembly);
                info[Params.Methods.ToString()] = GetMethods(func, assembly);
            }

            return info;
        }

        public static IFinPlusFunction GetConst(IFinPlusFunction func, Assembly assembly)
        {
            var p = new Function(string.Format("{0}.{1}", func[Params.FunctionName.ToString()].ToString(), Params.Methods.ToString()));
            if (func == null) return p;

            var type = Type(assembly, func[Params.FunctionName.ToString()].ToString());
            if (type == null) return p;

            foreach (var cons in type.GetConstructors(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly))
                if (!(cons.Name.Contains("_")))
                    p[cons.Name] = string.Format("({0})", string.Join(",", cons.GetParameters().Select(i => i.ParameterType.Name).ToArray()));

            return p;
        }

        public static IFinPlusFunction GetProperties(IFinPlusFunction func, Assembly assembly)
        {
            var p = new Function(string.Format("{0}.{1}",func[Params.FunctionName.ToString()].ToString(), Params.Properties.ToString()));
            if (func == null) return p;

            var type = Type(assembly, func[Params.FunctionName.ToString()].ToString());
            if (type == null) return p;

            foreach (var prop in type.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly))
                p[prop.Name] = " " + prop.PropertyType.Name;

            return p;
        }

        public static IFinPlusFunction GetMethods(IFinPlusFunction func, Assembly assembly)
        {
            var p = new Function(string.Format("{0}.{1}",func[Params.FunctionName.ToString()].ToString(), Params.Methods.ToString()));
            if (func == null) return p;

            var type = Type(assembly, func[Params.FunctionName.ToString()].ToString());
            if (type == null) return p;

            foreach (var meth in type.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly))
                if(!(meth.Name.Contains("_")))
                    p[meth.Name] = string.Format("({0})", string.Join(",", meth.GetParameters().Select(i => i.ParameterType.Name).ToArray()));

            return p;
        }

        public static Type Type(Assembly assembly, string name)
        {
            foreach (var type in assembly.GetExportedTypes())
                if (type.Name == name)
                    return type;
            return null;
        }
    }
}

























































































































































































//Copyright2013<jnrton>AllRightsReserved 
//Contact j.nrton@finpus